/*
 * My12306View.java
 */
package my12306;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimerTask;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import my12306.bean.PassengerInfo;
import my12306.bean.QueryResult;
import my12306.bean.Seats;
import my12306.db.SQLite;
import my12306.http.Consts;
import my12306.http.TrainInfo;
import my12306.table.CitySelectorCombox;
import my12306.table.DateChooser;
import my12306.table.KeyValueItem;
import org.jdesktop.application.Action;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.json.JSONException;
import org.slf4j.LoggerFactory;

/**
 * The application's main frame.
 */
public class My12306ViewMini extends FrameView implements IOptions {

    private final TrainClient trainClient = My12306App.getTrainClient();
    private final org.slf4j.Logger log = LoggerFactory.getLogger(getClass());
    protected final SimpleDateFormat sdfShort = new SimpleDateFormat("yyyy-MM-dd");
    protected final SimpleDateFormat sdfLong = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private OptionsBean options;
//    AutoThread autoTask;
    private ScheduledTask autoTask;
    private ScheduledTask bookTask;
    private ScheduledTask scheduledTask;
    private List<TrainInfo> trainsSelected;
    private PassengerInfoPanel passengerInfoTable;
    private TrainSelectDialog trainSelectDialog;
    private List<KeyValueItem> seatsSelected;
    private SeatSelectDialog seatSelectDialog;
    private java.util.Timer timer;
//    ResourceMap resourceMap = Application.getInstance(my12306.My12306App.class).
//            getContext().getResourceMap(My12306ViewMini.class);

    public My12306ViewMini(final SingleFrameApplication app) {
        super(app);
        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        //add window listener
        getFrame().setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        getFrame().addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                app.exit();
            }
        });
//        getFrame().setIconImage(resourceMap.getImageIcon("frame.imageicon").getImage());
        init();

    }

    private void init() {
        CitySelectorCombox.setupAutoComplete(txtFromCity);
        CitySelectorCombox.setupAutoComplete(txtToCity);
        txtFromCity.setColumns(30);
        txtToCity.setColumns(30);

        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 19);
        txtStartDate.setText(sdfShort.format(cal.getTime()));
        DateChooser dateChooser = DateChooser.getInstance(cal.getTime(), "yyyy-MM-dd");
        dateChooser.register(txtStartDate);
        /*
         * keep alive timer
         */
        getTimer().schedule(new TimerTask() {
            @Override
            public void run() {
                //call this method to keep the connection to server alive.
                log("Keeping alive...");
                try {
                    QueryResult qr = trainClient.confirmPassengerAction_getpassengerJson();
                    if (qr.getRawData().contains("<title>登录</title>")) {
                        log.info("可能超时了，正在处理...");
                        trainClient.checkLogin();
                    }
                } catch (Exception ex) {
                    log.error(ex.getLocalizedMessage(), ex);
                }
                log("Keep alive done.");
            }
        }, 0, getOptions().getKeepLive() * 60 * 1000);

        jSplitPane1.setLeftComponent(getPassengerInfoTable());
        getFrame().setTitle(getFrame().getTitle() + " - " + trainClient.getCurrentUser());
        jEditorPane1.setDocument(new HTMLEditorKit().createDefaultDocument());
        log("登录成功。");

    }

    /**
     * @return the options
     */
    public OptionsBean getOptions() {
        if (options == null) {
            options = new OptionsBean();
            options.setKeepAlive(OptionsBean.KEEPALIVEDEFAULT);
            options.setSleepTime(OptionsBean.SLEEPTIMEDEFAULT);
            options.setUserAgent(Consts.userAgentList.get(0));
            String big = trainClient.getCookieValue(OptionsBean.BIGipServerotswebKey);
            String session = trainClient.getCookieValue(OptionsBean.JSESSIONIDKey);
            getOptions().setCookies(big, session);

            options.addPropertyChangeListener(new PropertyChangeListener() {
                public void propertyChange(PropertyChangeEvent evt) {
                    String propertyName = evt.getPropertyName();
                    if (OptionsBean.USER_AGENT_PROPERTY.equals(propertyName)) {
                        trainClient.setUserAgent(evt.getNewValue().toString());
                    } else if (OptionsBean.COOKIES_PROPERTY.equals(propertyName)) {
                        if (!evt.getNewValue().equals(evt.getOldValue())) {
                            String[] newValues = (String[]) evt.getNewValue();
                            trainClient.setCookies(newValues[0], newValues[1]);
                        }
                    }
                }
            });
        }
        return options;
    }

    /**
     * @param options the options to set
     */
    public void setOptions(OptionsBean options) {
        this.options = options;
    }

    protected synchronized void showMsg(String msg) {
        JOptionPane.showMessageDialog(this.getFrame(), msg, "My12306", JOptionPane.WARNING_MESSAGE);
    }

    @Action
    public void showOptions() {
        if (optionBox == null) {
            JFrame mainFrame = My12306App.getApplication().getMainFrame();
            optionBox = new OptionsDialog(mainFrame, getOptions(), true);
            optionBox.setLocationRelativeTo(mainFrame);
            optionBox.setOption(getOptions());
        }
        setOptions(optionBox.showDialog());
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = My12306App.getApplication().getMainFrame();
            aboutBox = new My12306AboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        My12306App.getApplication().show(aboutBox);
    }

    protected PassengerInfoPanel getPassengerInfoTable() {
        if (passengerInfoTable == null) {
            passengerInfoTable = new PassengerInfoPanel();
            try {
                passengerInfoTable.setData(trainClient.getPassengerData());
            } catch (Exception ex) {
                log.error(ex.getLocalizedMessage(), ex);
            }
        }
        return passengerInfoTable;
    }

    protected List<PassengerInfo> getPassengers() {
        List<PassengerInfo> users = new ArrayList<PassengerInfo>();
        List<List<Object>> datas = getPassengerInfoTable().getModel().getData();
        for (int i = 0; i < datas.size(); i++) {
            //0         1       2       3       4        5           6
            //{"序号", "席别", "票种", "姓名", "证件类型", "证件号码", "手机号"};
            List<Object> data = datas.get(i);
            PassengerInfo user = new PassengerInfo();
            user.setFromStation(txtFromCity.getText().trim());
            user.setToStation(txtToCity.getText().trim());
            user.setID(data.get(5).toString());
            user.setIDType(((KeyValueItem) data.get(4)).getValue());
            user.setName(data.get(3).toString());
            user.setPhone(data.get(6).toString());
//            user.setSeatType(((KeyValueItem) data.elementAt(1)).getValue());
            user.setSeatType(((KeyValueItem) data.get(1)));
            user.setStartDate(txtStartDate.getText().trim());
            user.setTickType(((KeyValueItem) data.get(2)).getValue());
            user.setRangDate(jcbTime.getSelectedItem().toString());
            users.add(user);
        }
        return users;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jSplitPane3 = new javax.swing.JSplitPane();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        txtFromCity = new javax.swing.JTextField();
        txtToCity = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        txtStartDate = new javax.swing.JTextField();
        jLabel3 = new javax.swing.JLabel();
        jcbTime = new javax.swing.JComboBox();
        btnBook = new javax.swing.JButton();
        jLabel5 = new javax.swing.JLabel();
        jLabel7 = new javax.swing.JLabel();
        btnStop = new javax.swing.JButton();
        btnSchedule = new javax.swing.JButton();
        jLabel8 = new javax.swing.JLabel();
        txtTimeToRun = new javax.swing.JTextField();
        labSwap = new javax.swing.JLabel();
        btnSelectTrains = new javax.swing.JButton();
        txtTrains = new javax.swing.JTextField();
        jButton1 = new javax.swing.JButton();
        txtSeats = new javax.swing.JTextField();
        jScrollPane1 = new javax.swing.JScrollPane();
        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel2 = new javax.swing.JPanel();
        btnDownload = new javax.swing.JButton();
        btnAdd = new javax.swing.JButton();
        btnDelete = new javax.swing.JButton();
        jScrollPane3 = new javax.swing.JScrollPane();
        jEditorPane1 = new javax.swing.JEditorPane();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        toolsMenu = new javax.swing.JMenu();
        optionsMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setName("mainPanel"); // NOI18N

        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane2.setName("jSplitPane2"); // NOI18N
        jSplitPane2.setPreferredSize(new java.awt.Dimension(671, 436));

        jSplitPane3.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane3.setName("jSplitPane3"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(my12306.My12306App.class).getContext().getResourceMap(My12306ViewMini.class);
        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(resourceMap.getString("jPanel1.border.title"))); // NOI18N
        jPanel1.setName("jPanel1"); // NOI18N
        jPanel1.setPreferredSize(new java.awt.Dimension(735, 180));

        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
        jLabel1.setName("jLabel1"); // NOI18N

        txtFromCity.setText(resourceMap.getString("txtFromCity.text")); // NOI18N
        txtFromCity.setName("txtFromCity"); // NOI18N

        txtToCity.setText(resourceMap.getString("txtToCity.text")); // NOI18N
        txtToCity.setName("txtToCity"); // NOI18N

        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N

        jLabel4.setText(resourceMap.getString("jLabel4.text")); // NOI18N
        jLabel4.setName("jLabel4"); // NOI18N

        txtStartDate.setText(resourceMap.getString("txtStartDate.text")); // NOI18N
        txtStartDate.setName("txtStartDate"); // NOI18N

        jLabel3.setText(resourceMap.getString("jLabel3.text")); // NOI18N
        jLabel3.setName("jLabel3"); // NOI18N

        jcbTime.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "00:00--24:00", "00:00--06:00", "00:06--12:00", "00:12--18:00", "00:18--24:00" }));
        jcbTime.setName("jcbTime"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(my12306.My12306App.class).getContext().getActionMap(My12306ViewMini.class, this);
        btnBook.setAction(actionMap.get("bookAction")); // NOI18N
        btnBook.setText(resourceMap.getString("btnBook.text")); // NOI18N
        btnBook.setName("btnBook"); // NOI18N

        jLabel5.setText(resourceMap.getString("jLabel5.text")); // NOI18N
        jLabel5.setName("jLabel5"); // NOI18N

        jLabel7.setText(resourceMap.getString("jLabel7.text")); // NOI18N
        jLabel7.setName("jLabel7"); // NOI18N

        btnStop.setAction(actionMap.get("stopAction")); // NOI18N
        btnStop.setText(resourceMap.getString("btnStop.text")); // NOI18N
        btnStop.setName("btnStop"); // NOI18N

        btnSchedule.setAction(actionMap.get("scheduleAction")); // NOI18N
        btnSchedule.setText(resourceMap.getString("btnSchedule.text")); // NOI18N
        btnSchedule.setName("btnSchedule"); // NOI18N

        jLabel8.setText(resourceMap.getString("jLabel8.text")); // NOI18N
        jLabel8.setName("jLabel8"); // NOI18N

        txtTimeToRun.setText(resourceMap.getString("txtTimeToRun.text")); // NOI18N
        txtTimeToRun.setName("txtTimeToRun"); // NOI18N

        labSwap.setIcon(resourceMap.getIcon("labSwap.icon")); // NOI18N
        labSwap.setText(resourceMap.getString("labSwap.text")); // NOI18N
        labSwap.setToolTipText(resourceMap.getString("labSwap.toolTipText")); // NOI18N
        labSwap.setName("labSwap"); // NOI18N
        labSwap.setPreferredSize(new java.awt.Dimension(21, 21));
        labSwap.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                labSwapMouseClicked(evt);
            }
        });

        btnSelectTrains.setAction(actionMap.get("selectTrainsAction")); // NOI18N
        btnSelectTrains.setText(resourceMap.getString("btnSelectTrains.text")); // NOI18N
        btnSelectTrains.setName("btnSelectTrains"); // NOI18N

        txtTrains.setText(resourceMap.getString("txtTrains.text")); // NOI18N
        txtTrains.setName("txtTrains"); // NOI18N

        jButton1.setAction(actionMap.get("selectSeatAction")); // NOI18N
        jButton1.setText(resourceMap.getString("jButton1.text")); // NOI18N
        jButton1.setName("jButton1"); // NOI18N

        txtSeats.setText(resourceMap.getString("txtSeats.text")); // NOI18N
        txtSeats.setName("txtSeats"); // NOI18N

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(2, 2, 2)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jLabel1)
                            .addComponent(jLabel4)
                            .addComponent(jLabel5))
                        .addGap(10, 10, 10)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(txtFromCity, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(txtStartDate, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addGap(43, 43, 43)
                                .addComponent(labSwap, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(36, 36, 36)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jLabel3)
                                    .addComponent(jLabel2))
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(txtToCity, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(jcbTime, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE)))
                            .addComponent(txtTrains, javax.swing.GroupLayout.PREFERRED_SIZE, 433, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel8)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(txtTimeToRun, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel7)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(txtSeats, javax.swing.GroupLayout.PREFERRED_SIZE, 435, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 14, Short.MAX_VALUE)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap())
                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                            .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(btnBook, javax.swing.GroupLayout.DEFAULT_SIZE, 87, Short.MAX_VALUE)
                                .addComponent(btnStop, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(btnSelectTrains, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                            .addGap(10, 10, 10))
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                            .addComponent(btnSchedule, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addContainerGap()))))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(txtFromCity, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel2)
                                .addComponent(txtToCity, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(btnSelectTrains))
                            .addComponent(labSwap, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                    .addComponent(jcbTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(jLabel3))
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                    .addComponent(txtStartDate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(jLabel4)))
                            .addComponent(btnBook))
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGap(7, 7, 7)
                                .addComponent(btnStop))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                    .addComponent(txtTrains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(jLabel5)))))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addGap(67, 67, 67)))
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(6, 6, 6)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(txtSeats, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel7)
                            .addComponent(jButton1))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel8)
                            .addComponent(txtTimeToRun, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(35, 35, 35)
                        .addComponent(btnSchedule))))
        );

        jSplitPane3.setLeftComponent(jPanel1);

        jScrollPane1.setBorder(javax.swing.BorderFactory.createTitledBorder(resourceMap.getString("jScrollPane1.border.title"))); // NOI18N
        jScrollPane1.setName("jScrollPane1"); // NOI18N

        jSplitPane1.setDividerLocation(500);
        jSplitPane1.setName("jSplitPane1"); // NOI18N

        jPanel2.setName("jPanel2"); // NOI18N

        btnDownload.setAction(actionMap.get("downloadAction")); // NOI18N
        btnDownload.setText(resourceMap.getString("btnDownload.text")); // NOI18N
        btnDownload.setName("btnDownload"); // NOI18N

        btnAdd.setAction(actionMap.get("addAction")); // NOI18N
        btnAdd.setText(resourceMap.getString("btnAdd.text")); // NOI18N
        btnAdd.setName("btnAdd"); // NOI18N

        btnDelete.setAction(actionMap.get("deleteAction")); // NOI18N
        btnDelete.setText(resourceMap.getString("btnDelete.text")); // NOI18N
        btnDelete.setName("btnDelete"); // NOI18N

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(btnDelete, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(btnAdd, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(btnDownload, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(btnDownload)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(btnAdd)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btnDelete)
                .addGap(19, 19, 19))
        );

        jSplitPane1.setRightComponent(jPanel2);

        jScrollPane1.setViewportView(jSplitPane1);

        jSplitPane3.setRightComponent(jScrollPane1);

        jSplitPane2.setLeftComponent(jSplitPane3);

        jScrollPane3.setName("jScrollPane3"); // NOI18N

        jEditorPane1.setContentType("text/html"); // NOI18N
        jEditorPane1.setName("jEditorPane1"); // NOI18N
        jScrollPane3.setViewportView(jEditorPane1);

        jSplitPane2.setRightComponent(jScrollPane3);

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 608, Short.MAX_VALUE)
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 468, Short.MAX_VALUE)
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        toolsMenu.setText(resourceMap.getString("toolsMenu.text")); // NOI18N
        toolsMenu.setName("toolsMenu"); // NOI18N

        optionsMenuItem.setAction(actionMap.get("showOptions")); // NOI18N
        optionsMenuItem.setText(resourceMap.getString("optionsMenuItem.text")); // NOI18N
        optionsMenuItem.setName("optionsMenuItem"); // NOI18N
        toolsMenu.add(optionsMenuItem);

        menuBar.add(toolsMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 608, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 438, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    private void labSwapMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_labSwapMouseClicked
        String tmpStr = txtFromCity.getText();
        txtFromCity.setText(txtToCity.getText());
        txtToCity.setText(tmpStr);
    }//GEN-LAST:event_labSwapMouseClicked

    public synchronized void log(String msg) {
        try {
            //StyledDocument doc = textPane.getStyledDocument();
//            Document doc = jEditorPane1.getDocument();
//            doc.insertString(doc.getLength(), "\n", null);
//            doc.insertString(doc.getLength(), msg, null);
//            jEditorPane1.setCaretPosition(doc.getLength());
            HTMLDocument htmlDoc = (HTMLDocument) jEditorPane1.getDocument();
            htmlDoc.insertAfterEnd(htmlDoc.getCharacterElement(htmlDoc.getEndPosition().getOffset()), msg);
            htmlDoc.insertAfterEnd(htmlDoc.getCharacterElement(htmlDoc.getEndPosition().getOffset()), "<br/>");
            jEditorPane1.setCaretPosition(htmlDoc.getLength());
            statusMessageLabel.setText(msg);
            log.info(msg);
        } catch (Exception ex) {
        }
    }

    private void stop() {
        if (autoTask != null) {
            autoTask.setStop();
//            autoTask = null;
            log("自动订票系统已停止。");
        }
        if (bookTask != null) {
            bookTask.setStop();
//            bookTask = null;
            log("订票系统已停止。");
        }
        if (scheduledTask != null) {
            scheduledTask.setStop();
            scheduledTask.cancel();
//            scheduledTask = null;
            log("定时订票系统已停止。");
        }
        getTimer().purge();
    }

    private void schedule(ScheduledTask task, Date timeToRun) {
        log("submit secheduled task...");
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            getTimer().schedule(task, timeToRun);
            log("task secheduled at " + sdf.format(timeToRun));
        } catch (Exception ex) {
            log.error(ex.getLocalizedMessage(), ex);
        }

    }

    @Action
    public void selectSeatAction() {
        setSeatsSelected(getSeatSelectDialog().showDialog());
        StringBuilder sb = new StringBuilder();
        for (KeyValueItem item : getSeatsSelected()) {
            sb.append(item.getKey()).append(",");
        }
        txtSeats.setText(sb.toString());
        log(String.format("已选择%d个席别。", getSeatsSelected().size()));
    }

    @Action
    public void selectTrainsAction() {
        // My12306App.getApplication().show(trainSelect);
        try {
            setTrains(getTrainSelectDialog().showDialog());
            StringBuilder sb = new StringBuilder();
            for (TrainInfo info : getSelectedTrains()) {
                sb.append(info.getTrainCode()).append(",");
            }
            txtTrains.setText(sb.toString());
            log(String.format("已选择%d班列车。", getSelectedTrains().size()));
        } catch (Exception ex) {
            log.error(ex.getLocalizedMessage(), ex);
        }
    }

    @Action
    public void scheduleAction() {
        if (scheduledTask != null && !scheduledTask.isStoped()) {
            log("Task is running, please stop it first.");
            return;
        }
        log("正在启动定时订票系统...");
        Calendar cal = Calendar.getInstance(Locale.CHINA);


        String today = sdfShort.format(cal.getTime());
        Date timeToRun;
        try {
            timeToRun = sdfLong.parse(today + " " + txtTimeToRun.getText().trim());
            scheduledTask = new ScheduledTask(this, getPassengers(), getSelectedTrains());
            schedule(scheduledTask, timeToRun);
        } catch (ParseException ex) {
            log.error(ex.getLocalizedMessage(), ex);
        }
    }

    @Action
    public void bookAction() {
        if (bookTask != null && !bookTask.isStoped()) {
            log("Task is running, please stop it first.");
            return;
        }
        log("正在准备订票...");
        Date timeToRun = new Date();
        try {
            bookTask = new ScheduledTask(this, getPassengers(), getSelectedTrains());
            schedule(bookTask, timeToRun);
        } catch (Exception ex) {
            log.error(ex.getLocalizedMessage(), ex);
        }
    }

    @Action
    public void stopAction() {
        log("正在准备停止订票...");
        stop();
    }

    @Action
    public void downloadAction() {
        log("正在下载联系人信息...");
        try {
            getPassengerInfoTable().setData(trainClient.getPassengerData());
        } catch (JSONException ex) {
            log.error(ex.getLocalizedMessage(), ex);
        }
        log("已下载完成。");
    }

    @Action
    public void addAction() {
        log("正在添加乘车人...");
        if (getPassengerInfoTable().getModel().getRowCount() >= 5) {
            showMsg("一次最多只能预定5张车票。");
            return;
        }
        List<Object> row = new ArrayList<Object>();
        row.add("" + (getPassengerInfoTable().getModel().getRowCount() + 1));
        row.add(Seats.getSeat("1"));
        row.add(KeyValueItem.getTicketType("1"));
        row.add("您的姓名");
        row.add(KeyValueItem.getIDType("1"));
        row.add("您的证件号码");
        row.add("您的手机号码");
        getPassengerInfoTable().add(row);
        log("已添加完成，请完善资料。");
    }

    @Action
    public void deleteAction() {
        if (getPassengerInfoTable().getTable().getSelectedRowCount() > 0) {
            int index = getPassengerInfoTable().getTable().getSelectedRow();
            log("正在删除...");
            getPassengerInfoTable().deleteSelected();
            log(String.format("第%d行数据已经删除。", index + 1));
        } else {
            log("请先选择数据。");
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAdd;
    private javax.swing.JButton btnBook;
    private javax.swing.JButton btnDelete;
    private javax.swing.JButton btnDownload;
    private javax.swing.JButton btnSchedule;
    private javax.swing.JButton btnSelectTrains;
    private javax.swing.JButton btnStop;
    private javax.swing.JButton jButton1;
    private javax.swing.JEditorPane jEditorPane1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JSplitPane jSplitPane3;
    private javax.swing.JComboBox jcbTime;
    private javax.swing.JLabel labSwap;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JMenuItem optionsMenuItem;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JMenu toolsMenu;
    private javax.swing.JTextField txtFromCity;
    private javax.swing.JTextField txtSeats;
    private javax.swing.JTextField txtStartDate;
    private javax.swing.JTextField txtTimeToRun;
    private javax.swing.JTextField txtToCity;
    private javax.swing.JTextField txtTrains;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;
    private OptionsDialog optionBox;

    /**
     * @return the trains
     */
    public List<TrainInfo> getSelectedTrains() {
        if (trainsSelected == null) {
            trainsSelected = new ArrayList<TrainInfo>();
        }
        return trainsSelected;
    }

    /**
     * @param trains the trains to set
     */
    public void setTrains(List<TrainInfo> trains) {
        this.trainsSelected = trains;
    }

    /**
     * @return the seatsSelected
     */
    public List<KeyValueItem> getSeatsSelected() {
        if (seatsSelected == null) {
            seatsSelected = new ArrayList<KeyValueItem>();
        }
        return seatsSelected;
    }

    /**
     * @param seatsSelected the seatsSelected to set
     */
    public void setSeatsSelected(List<KeyValueItem> seatsSelected) {
        this.seatsSelected = seatsSelected;
    }

    /**
     * @return the seatSelectDialog
     */
    public SeatSelectDialog getSeatSelectDialog() {
        if (seatSelectDialog == null) {
            JFrame mainFrame = My12306App.getApplication().getMainFrame();
            seatSelectDialog = new SeatSelectDialog(this);
            seatSelectDialog.setLocationRelativeTo(mainFrame);
        }
        return seatSelectDialog;
    }

    /**
     * @param seatSelectDialog the seatSelectDialog to set
     */
    public void setSeatSelectDialog(SeatSelectDialog seatSelectDialog) {
        this.seatSelectDialog = seatSelectDialog;
    }

    /**
     * @return the trainSelectDialog
     */
    public TrainSelectDialog getTrainSelectDialog() {
        if (trainSelectDialog == null) {
            JFrame mainFrame = My12306App.getApplication().getMainFrame();
            trainSelectDialog = new TrainSelectDialog(this);
            trainSelectDialog.setLocationRelativeTo(mainFrame);
        }
        trainSelectDialog.setFrom(txtFromCity.getText().trim());
        trainSelectDialog.setTo(txtToCity.getText().trim());
        trainSelectDialog.setStartDate(txtStartDate.getText().trim());
        trainSelectDialog.setStartTime(jcbTime.getSelectedItem().toString());
        return trainSelectDialog;
    }

    /**
     * @param trainSelectDialog the trainSelectDialog to set
     */
    public void setTrainSelectDialog(TrainSelectDialog trainSelectDialog) {
        this.trainSelectDialog = trainSelectDialog;
    }

    /**
     * @return the timer
     */
    public java.util.Timer getTimer() {
        if (timer == null) {
            timer = new java.util.Timer("AutoTimer");
        }
        return timer;
    }
}
